/*
 * @Author: gggg 1263457581@qq.com
 * @Date: 2025-06-09 10:41:18
 * @LastEditors: gggg 1263457581@qq.com
 * @LastEditTime: 2025-06-10 17:53:22
 * @FilePath: /algorithm-and-data-struct/pool/MemoryPool.cpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <iostream>
#include <vector>
#include <mutex>
#include <memory>
#include <stdexcept>

template<typename T, size_t BlockSize = 32>
class MemoryPool {
private:
    // alignof(T) 获取T类型字节对齐值
    // alignas 强制该结构提按照类型T对其要求进行内存对齐
    struct alignas(alignof(T)) Block {
        char data[sizeof(T)];
    };

    std::vector<Block*> blocks;
    std::vector<T*> freeList;
    std::mutex mtx;

public:
    MemoryPool() {
        // Initialize the memory pool with a single block
        auto block = new Block();
        blocks.push_back(block);
    }
    ~MemoryPool() {
        for (auto block : blocks) {
            delete block;
        }
    }

    T* allocate() {
        std::lock_guard<std::mutex> lock(mtx);
        if (freeList.empty()) {
            // Allocate a new block
            auto block = new Block();
            blocks.push_back(block);
            //原地构造 new (pointer) Type(args)   pointer已经分配好的内存  type： 构造的对象类型   args： 构造函数的参数
            //char buffer[sizeof(MyClass)]; // 预先分配内存
            //MyClass* obj = new (buffer) MyClass(); // 在 buffer 上构造对象
            return new (block->data) T();  // Placement new
        } else {
            T* obj = freeList.back();
            freeList.pop_back();
            return obj;
        }
    }

    void deallocate(T* obj) {
        std::lock_guard<std::mutex> lock(mtx);
        obj->~T();  // Explicitly call destructor  显示调用析构函数
        freeList.push_back(obj);
    }
};

int main() {
    MemoryPool<int> pool;

    int* a = pool.allocate();
    *a = 42;
    std::cout << *a << std::endl;

    pool.deallocate(a);

    int* b = pool.allocate();  // Reuses the same memory
    std::cout << *b << std::endl;  // May be 42 if not initialized

    pool.deallocate(b);

    return 0;
}